#ifndef xpack_ttyctrl_text_line
#define xpack_ttyctrl_text_line
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::ttyctrl_text_line::inc
#include"algo/insert.hpp"
#include"algo/remove.hpp"
#include"define/base_type.hpp"
#include"macro/xexport.hpp"
#include"macro/xindex_rollback.hpp"
#include"macro/xmodify.hpp"
#include"macro/xstruct.hpp"
#include"memop/copy.hpp"
#include"memop/swap.hpp"
#include"utils/shared_array.hpp"
#pragma pop_macro("xuser")

namespace mixc::ttyctrl_text_line{
    namespace inc{
        inline uxx tty_width(char16_t value){
            return value < 0xff ? 1 : 2;
        }
    }

    xstruct(
        xname(text_line),
        xprif(m_text          ,   inc::shared_array<char16_t>),
        xprif(m_left          ,   u16),
        xprif(m_top           ,   u16),
        xprif(m_column        ,   u16),
        xprif(m_cursor_column ,   u16),
        xprif(m_cursor_index  ,   u32),
        xprif(m_length        ,   u32)
    )
        enum{ over_boundary = true, };

        xprops()
            xprigetx(capacity, uxx){
                xr{
                    return xthe.m_text->length;
                }
            };

            xpubget_priset(length, uxx);
            xpubget_pubset(left, u16);
            xpubget_pubset(top, u16);
            xpubget_pubset(column, u16);
            xpubget_pubset(cursor_column, u16);
            xpubget_pubset(cursor_index, u16);
        $

        xprops_operator()
    public:
        text_line() : 
            m_text(::length{4}){
        }

        char16_t & operator[](ixx index){
            xindex_rollback(xthe->length, index);
            return xthe.m_text[uxx(index)];
        }


        bool go_left(){
            if (xthe.m_cursor_column != xthe.m_left){
                auto v = xthe[m_cursor_index];
                xthe.m_cursor_column -= inc::tty_width(v);

                if (xthe.m_cursor_column + 1 == xthe.m_left){ // over bound
                    xthe.m_cursor_column += 1;
                }
            }
            if (xthe.m_cursor_index != 0){
                xthe.m_cursor_index -= 1;
                return not over_boundary;
            }
            return over_boundary;
        }

        bool go_right(){
            if (auto bound = m_left + m_column; m_cursor_column != bound){
                auto v = xthe[m_cursor_index];
                xthe.m_cursor_column += inc::tty_width(v);

                if (xthe.m_cursor_column - 1 == bound){ // over bound
                    xthe.m_cursor_column -= 1;
                }
            }
            if (xthe.m_cursor_index != xthe->length){
                xthe.m_cursor_index += 1;
                return not over_boundary;
            }
            return over_boundary;
        }

        void go_home(){
            xthe.m_cursor_column = xthe.m_left;
            xthe.m_cursor_index  = 0;
        }

        void go_end(){
            xthe.m_cursor_column = xthe.m_left + xthe.m_column;
            xthe.m_cursor_index  = xthe->length;
        }

        bool backspace(){
            if (go_left() == over_boundary){
                return over_boundary;
            }
            return xthe.compact();
        }

        bool deletes(){
            if (xthe.m_cursor_index == xthe->length){
                return over_boundary;
            }
            return xthe.compact();
        }

        void write(char16_t value){
            uxx new_length = inc::insert(xthe.m_text, xthe.m_cursor_index, value);

            if (xthe->capacity == new_length){
                xthe.resize(new_length * 4);
            }
        }
    private:
        bool compact(){
            if (xthe->length = inc::remove(xthe.m_text, xthe.m_cursor_index); 
                xthe->capacity == xthe->length * 4
            ){
                xthe.resize(xthe.m_length);
            }
            return not over_boundary;
        }

        void resize(uxx new_length){
            inc::shared_array<char16_t> compact {
                ::length{new_length}
            };
            inc::copy(compact, xthe.m_text, compact->length);
            xthe.m_text.swap(xmodify(compact));
        }
    $
}
#endif

xexport(mixc::ttyctrl_text_line::text_line)